#include "MemoryPCH.h"

#include "MM_MemoryManager.h"
#include "MM_MemoryDefaultAllocPolicy.h"
#include "MM_MemoryNedAllocPolicy.h"
#include "MM_MemoryTbbAllocPolicy.h"

using namespace Memory;

MM_MemoryManager* MM_MemoryManager::ms_pkMemManager = NULL;
//----------------------------------------------------------------
//MM_MemoryManager
//----------------------------------------------------------------
MM_MemoryManager& MM_MemoryManager::GetSingleton()
{
	return *(ms_pkMemManager);
}
//----------------------------------------------------------------
bool MM_MemoryManager::Init()
{
	ms_pkMemManager = new MM_MemoryManager;

	return true;
}
//----------------------------------------------------------------
bool MM_MemoryManager::UnInit()
{
	delete ms_pkMemManager;
	ms_pkMemManager = NULL;

	return true;
}
//----------------------------------------------------------------
void MM_MemoryManager::SetMemoryAllocPolicyType(uint32_t uiPolicyType)
{
	m_uiMemoryPolicyType = uiPolicyType;
}
//----------------------------------------------------------------
void MM_MemoryManager::SetMemoryTrackerOpen(bool bOpen)
{
	m_bMemoryTrackerOpen = bOpen;
}
//----------------------------------------------------------------
void* MM_MemoryManager::Allocate(size_t stSize, size_t stAlignment,uint32_t uiMemoryPool, const char *pcSourceFile /* = 0 */, int32_t iSourceLine /* = 0 */, const char* pcFunction /* = 0 */)
{
	void* ptr = NULL;
	
	switch(m_uiMemoryPolicyType)
	{
	case MAPT_DEFAUL:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryDefaultAllocPolicy::allocBytes(stSize);
			else
				ptr = MM_MemoryDefaultAllocPolicy::allocBytesAligned(stSize,stAlignment);
		}
		break;
	case MAPT_NED:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryNedAllocPolicy::allocBytes(stSize);
			else
				ptr = MM_MemoryNedAllocPolicy::allocBytesAligned(stSize,stAlignment);
		}
		break;
	case MAPT_TBB:
		{
			if(stAlignment < 0)
				ptr = MM_MemoryTbbAllocPolicy::allocBytes(stSize);
			else
				ptr = MM_MemoryTbbAllocPolicy::allocBytesAligned(stSize,stAlignment);
		}
		break;
	default:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryDefaultAllocPolicy::allocBytes(stSize);
			else
				ptr = MM_MemoryDefaultAllocPolicy::allocBytesAligned(stSize,stAlignment);
		}
	}

	if(m_bMemoryTrackerOpen)
	{
		m_kMemoryTracker.RecordAlloc(ptr, stSize, uiMemoryPool, pcSourceFile, iSourceLine, pcFunction);
	}

	return ptr;
}
//----------------------------------------------------------------
void* MM_MemoryManager::Reallocate( void* pvMem, size_t stSize, size_t stAlignment,uint32_t uiMemoryPool, const char *pcSourceFile /*= 0*/, int32_t iSourceLine /*= 0*/, const char* pcFunction /*= 0*/ )
{
	void* ptr = NULL;

	if(m_bMemoryTrackerOpen)
	{
		m_kMemoryTracker.RecordDealloc(pvMem);
	}

	switch(m_uiMemoryPolicyType)
	{
	case MAPT_DEFAUL:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryDefaultAllocPolicy::reallocBytes(pvMem,stSize);
			else
				ptr = MM_MemoryDefaultAllocPolicy::reallocBytesAligned(pvMem,stSize,stAlignment);
		}
		break;
	case MAPT_NED:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryNedAllocPolicy::reallocBytes(pvMem,stSize);
			else
				ptr = MM_MemoryNedAllocPolicy::reallocBytesAligned(pvMem,stSize,stAlignment);
		}
		break;
	case MAPT_TBB:
		{
			if(stAlignment < 0)
				ptr = MM_MemoryTbbAllocPolicy::reallocBytes(pvMem,stSize);
			else
				ptr = MM_MemoryTbbAllocPolicy::reallocBytesAligned(pvMem,stSize,stAlignment);
		}
		break;
	default:
		{
			if(stAlignment == 0)
				ptr = MM_MemoryDefaultAllocPolicy::reallocBytes(pvMem,stSize);
			else
				ptr = MM_MemoryDefaultAllocPolicy::reallocBytesAligned(pvMem,stSize,stAlignment);
		}
	}

	if(m_bMemoryTrackerOpen)
	{
		m_kMemoryTracker.RecordAlloc(ptr, stSize, uiMemoryPool, pcSourceFile, iSourceLine, pcFunction);
	}

	return ptr;
}
//----------------------------------------------------------------
void MM_MemoryManager::Deallocate(void* pvMem,size_t stAlignment)
{
	if(m_bMemoryTrackerOpen)
	{
		m_kMemoryTracker.RecordDealloc(pvMem);
	}
	
	switch(m_uiMemoryPolicyType)
	{
	case MAPT_DEFAUL:
		{
			if(stAlignment == 0)
				MM_MemoryDefaultAllocPolicy::deallocBytes(pvMem);
			else
				MM_MemoryDefaultAllocPolicy::deallocBytesAligned(pvMem,stAlignment);
		}
		break;
	case MAPT_NED:
		{
			if(stAlignment == 0)
				MM_MemoryNedAllocPolicy::deallocBytes(pvMem);
			else
				MM_MemoryNedAllocPolicy::deallocBytesAligned(pvMem,stAlignment);
		}
		break;
	case MAPT_TBB:
		{
			if(stAlignment < 0)
				MM_MemoryTbbAllocPolicy::deallocBytes(pvMem);
			else
				MM_MemoryTbbAllocPolicy::deallocBytesAligned(pvMem,stAlignment);
		}
		break;
	default:
		{
			if(stAlignment == 0)
				MM_MemoryDefaultAllocPolicy::deallocBytes(pvMem);
			else
				MM_MemoryDefaultAllocPolicy::deallocBytesAligned(pvMem,stAlignment);
		}
	}
}
//----------------------------------------------------------------
size_t MM_MemoryManager::GetMaxAllocationSize()
{
	switch(m_uiMemoryPolicyType)
	{
	case MAPT_DEFAUL:
		return MM_MemoryDefaultAllocPolicy::getMaxAllocationSize();
	case MAPT_NED:
		return MM_MemoryNedAllocPolicy::getMaxAllocationSize();
	case MAPT_TBB:
		return MM_MemoryTbbAllocPolicy::getMaxAllocationSize();
	default:
		return MM_MemoryDefaultAllocPolicy::getMaxAllocationSize();
	}
}
//----------------------------------------------------------------
MM_MemoryManager::MM_MemoryManager()
{
	m_uiMemoryPolicyType = MAPT_DEFAUL;
	m_bMemoryTrackerOpen = false;
}